package com.gee.spring.cloud.feign.flow.binding;

import org.springframework.beans.factory.BeanFactory;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * desc:
 *
 * @author gee
 * @since 2021-03-31 09:25:17
 */
public class FeignFlowProxy<T> implements InvocationHandler, Serializable {

    private Class<T> feignFlowInterface;
    private final Map<Method, FeignFlowMethod> methodCache;
    private final BeanFactory beanFactory;
    private final ThreadPoolExecutor feignFlowThreadPoolExecutor;
    public FeignFlowProxy(Class<T> feignFlowInterface, Map<Method,
                          FeignFlowMethod> methodCache,
                          BeanFactory beanFactory,
                          ThreadPoolExecutor feignFlowThreadPoolExecutor) {
        this.feignFlowInterface = feignFlowInterface;
        this.methodCache = methodCache;
        this.beanFactory = beanFactory;
        this.feignFlowThreadPoolExecutor = feignFlowThreadPoolExecutor;
    }

    public Class<T> getFeignFlowInterface() {
        return feignFlowInterface;
    }

    public void setFeignFlowInterface(Class<T> feignFlowInterface) {
        this.feignFlowInterface = feignFlowInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args): cachedInvoker(method).execute(proxy, args);
    }

    private FeignFlowMethod cachedInvoker(Method method){
        FeignFlowMethod invoker = methodCache.get(method);
        return invoker !=null ? invoker :
                this.methodCache.computeIfAbsent(method, m ->
                        new FeignFlowMethod(method,beanFactory,feignFlowThreadPoolExecutor)
                );
    }
}
